home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Frameworks / Dragonsmith 1.1.1 / Base files / Utilities / FileUtils.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-01-15  |  12.3 KB  |  347 lines  |  [TEXT/KAHL]

  1. /*
  2.     FileUtils.c
  3.     
  4.     Created    05 May 1992    Extracted from Dragon.c
  5.     Modified    28 May 1992    Changed parameters of FREFTypes
  6.                         Other very minor changes
  7.             29 May 1992    Added RefNumToFSSpec function — I finally figured out how to get an FSSpec from a path refNum
  8.             02 Aug 1992    Added FSpToPB, FSpToPBCatInfo, PBToFSp, and PBToFSpCatInfo — but they haven't been tested!
  9.             05 Aug 1992    Extensive rewrites and some testing of the FSSpec <=> PBRecUnion conversion functions — what I
  10.                             tested seemed to work just fine, but then I didn't test directories…
  11.             06 Aug 1992    Tuned up conversion functions
  12.             09 Aug 1992    FREFTypes now takes a parameter — the refnum of the resource fork to look in
  13.                         Added FSpFindFolder
  14.             16 Aug 1992    Fixed problems with ioDirID and ioFDirIndex in PBToFSpCatInfo
  15.             04 Sep 1992    Added FSpRefreshFinderDisplay (and it works!)
  16.             09 Sep 1992    Fixed bug in FREFTypes — it returned garbage if there were no 'FREF' resources
  17.             11 Sep 1992    Extracted PBToFSp, FSpType, and FSpOpenableType — Dragonsmith doesn't need them
  18.             18 Apr 1993    Rewrote PBToFSpCatInfo to overcome bug (?) in PBMakeFSSpec with directories on shared volumes
  19.                             — thanks to Paul van Mulbregt for pointing out the problem (which I should have spotted myself!)
  20.             30 May 1993    Fixed FREFTypes — it was DisposHandle'ing a resource (oops)
  21.             08 Aug 1993    Brought in DirectoryContentsLoop from its source file
  22.                         Added some safety measures to paramblock initializations
  23.             14 Aug 1993    Fiddled with code to get it to compile with type-checked <MacHeaders>
  24.             
  25.     Copyright © 1992–1993 by Paul M. Hoffman
  26.     Send comments or suggestions to paul.hoffman@umich.edu -or- dragonsmith@umich.edu
  27.     
  28.     This source code may be freely used, altered, and distributed in any way as long as:
  29.         1.    It is GIVEN away rather than sold (except as expressly permitted by the author)
  30.         2.    This statement and the above copyright notice are left intact.
  31.  
  32. */
  33.  
  34. #include    "FileUtils.h"
  35. #include    "StringUtils.h"
  36.  
  37. void FSpRefreshFinderDisplay (FSSpec *fss)
  38. {
  39.     // Given an FSSpec to a file, tell the Finder to update its display of the file's icon — also works for directories
  40.     // There will be a brief delay before the change is shown.  Experience indicates that the delay is noticeably longer
  41.     //    if the only change is in the case (upper vs. lower) of the file's name
  42.     
  43.     CInfoPBRec        pb;
  44.     OSErr            err;
  45.     unsigned long        secs;
  46.     
  47.     // Fill in the parameter block so we get info on the parent directory rather than the file/folder itself
  48.     pb.hFileInfo.ioCompletion = NULL;
  49.     pb.hFileInfo.ioNamePtr = NULL;
  50.     pb.hFileInfo.ioVRefNum = fss->vRefNum;
  51.     pb.hFileInfo.ioFVersNum = 0;                // To be on the safe side
  52.     pb.hFileInfo.ioFDirIndex = 0;
  53.     pb.hFileInfo.ioDirID = fss->parID;
  54.     
  55.     // Get info on the parent directory
  56.     if (PBGetCatInfoSync (&pb) == noErr) {
  57.         // Now change the parent directory's modified date
  58.         GetDateTime (&secs);
  59.         pb.dirInfo.ioDrMdDat = (unsigned long) secs;
  60.         (void) PBSetCatInfoSync (&pb);
  61.     }
  62. }
  63.  
  64. OSErr FSpOpenDataFork (FSSpec *fss, short *refNum, char *perm)
  65. {
  66.     // Open a file's data fork with fsRdPerm or (if possible) fsRdWrPerm
  67.     
  68.     OSErr    err;
  69.     char        permWanted = *perm;
  70.     
  71.     err = FSpOpenDF (fss, *perm, refNum);
  72.     if (err == noErr)
  73.         return err;
  74.     if ((err == opWrErr || err == permErr) && *perm == fsRdWrPerm) {
  75.         err = FSpOpenDF (fss, fsRdPerm, refNum);
  76.         *perm = fsRdPerm;
  77.     }
  78.     return err;
  79. }
  80.  
  81. OSErr FSpOpenResFork (FSSpec *fss, short *refNum, char *perm)
  82. {
  83.     // Open a file's resource fork with fsRdPerm or (if possible) fsRdWrPerm
  84.     
  85.     OSErr    err;
  86.     char        permWanted = *perm;
  87.     
  88.     *refNum = FSpOpenResFile (fss, *perm);
  89.     err = ResError ();
  90.     if (err == noErr)
  91.         return err;
  92.     if ((err == opWrErr || err == permErr) && *perm == fsRdWrPerm) {
  93.         *refNum = FSpOpenResFile (fss, fsRdPerm);
  94.         err = ResError ();
  95.         *perm = fsRdPerm;
  96.     }
  97.     return err;
  98. }
  99.  
  100. OSErr FSpFindFolder (OSType folderType, FSSpec *fss)
  101. {
  102.     // NOTE:    This function does NOT return an FSSpec to the folder in question; rather, it returns an FSSpec to an unnamed
  103.     //        file IN THAT FOLDER.  In other words, just fill in the name field of the FSSpec returned to get at a file in the folder
  104.     // If an error happens, *fss is not affected
  105.     
  106.     short    foundVRefNum;
  107.     long        foundDirID;
  108.     OSErr    err;
  109.     
  110.     err = FindFolder (kOnSystemDisk, folderType, kCreateFolder, &foundVRefNum, &foundDirID);
  111.     if (err == noErr) {
  112.         fss->vRefNum = foundVRefNum;
  113.         fss->parID = foundDirID;
  114.     }
  115.     return err;
  116. }
  117.  
  118. OSErr FSpToPB (PBRecUnion *pb, FSSpec *fss, Boolean resolveAFs, Boolean followAFChain, Boolean *wasAF)
  119. {
  120.     OSErr    err = noErr;
  121.     Boolean    isFolder;
  122.     
  123.     // Check for a NULL name pointer — prob. the most common mistake I make when using PB's
  124.     if (pb->h.fileParam.ioNamePtr == NULL)
  125.         return bdNamErr;        // This seems like a reasonable error code to use…
  126.         
  127.     if (resolveAFs)
  128.         err = ResolveAliasFile (fss, followAFChain, &isFolder, wasAF);
  129.     if (err == noErr) {
  130.         pb->h.fileParam.ioVRefNum = fss->vRefNum;
  131.         pb->h.fileParam.ioDirID = fss->parID;
  132.         pb->h.fileParam.ioFVersNum = 0;                        // To be on the safe side
  133.         SmartCopyPStr (fss->name, pb->h.fileParam.ioNamePtr);    // This ensures that .ioNamePtr points to a string exactly
  134.                                                         //    equivalent to fss->name
  135.     }
  136.     return err;
  137. }
  138.  
  139. OSErr FSpToPBCatInfo (PBRecUnion *pb, FSSpec *fss, Boolean resolveAFs, Boolean followAFChain, Boolean *wasAF)
  140. {
  141.     OSErr    err = noErr;
  142.     Boolean    isFolder;
  143.     
  144.     err = FSpToPB (pb, fss, resolveAFs, followAFChain, wasAF);
  145.     if (err == noErr) {
  146.         pb->c.hFileInfo.ioFDirIndex = 0;    // No indexing
  147.         err = PBGetCatInfoSync (&pb->c);
  148.     }
  149.     return err;
  150. }
  151.  
  152. OSErr PBToFSpCatInfo (PBRecUnion *pb, FSSpec *fss, Boolean resolveAFs, Boolean followAFChain, Boolean *wasAF)
  153. {    
  154.     // NOTE:    *wasAF will contain garbage if the error returned != noErr
  155.  
  156.     OSErr    err;
  157.     long        dirIDOrFileNum, ioDirIDWas;
  158.     Ptr        ioMiscWas;
  159.     short    ioFDirIndexWas;
  160.     Boolean    isFolder;
  161.     
  162.     // ASSERT — the ioNamePtr, ioVRefNum, ioFDirIndex, and ioDirID fields in *pb are valid
  163.     
  164.     // Check for a NULL name pointer — prob. the most common mistake I make when using PB's
  165.     if (pb->h.fileParam.ioNamePtr == NULL)
  166.         return bdNamErr;        // This seems like a reasonable error code to use…
  167.         
  168.     err = PBGetCatInfoSync (&pb->c);
  169.     if (err == noErr) {
  170.  
  171.         // ASSERT —    Most of the fields in *pb are now valid (unless the doc is an alias file and resolveAFs == TRUE,
  172.         //            in which case we've got the wrong file — calling ResolveAliasFile below will fix this, though, so don't worry!)
  173.     
  174.         // Now we're ready to make an FSSpec out of the paramblock
  175.         
  176.         // Calling PBMakeFSSpec here leads to problems on other shared volumes, so we do it by hand
  177.         
  178.         fss->parID = pb->c.hFileInfo.ioFlParID;
  179.         
  180.         // If resolveAFs == TRUE, then we need to check to see if this is an alias file — we can't
  181.         //    eliminate any file types, since in the future there may exist aliases to things (like maybe
  182.         //    mailboxes, in OCE) that didn't exist at the time this code was written.  We can, however,
  183.         //    be sure that only files can be alias files (kinda obvious, ain't it?)
  184.         
  185.         *wasAF = FALSE;
  186.  
  187.         if (err == noErr && resolveAFs && PBIsAliasFile (pb)) {
  188.             err = ResolveAliasFile (fss, followAFChain, &isFolder, wasAF);
  189.             if (err == noErr && *wasAF) {
  190.                 // If this was an alias file, we need to call PBGetCatInfo once more for the actual file
  191.                 pb->c.hFileInfo.ioVRefNum = fss->vRefNum;
  192.                 pb->c.hFileInfo.ioDirID = fss->parID;
  193.                 
  194.                 ioFDirIndexWas = pb->c.hFileInfo.ioFDirIndex;    // Save the value in ioFDirIndex
  195.                 pb->c.hFileInfo.ioFDirIndex = 0;                // Zero ioFDirIndex so PBGetCatInfo won't use indexing
  196.                 
  197.                 // You don't need to copy fss->name to .ioNamePtr here — PBGetCatInfo will do it for us
  198.                 err = PBGetCatInfoSync (&pb->c);
  199.                 
  200.                 pb->c.hFileInfo.ioFDirIndex = ioFDirIndexWas;    // Restore ioFDirIndex
  201.             }
  202.         }
  203.     }
  204.     return err;
  205. }
  206.  
  207. TypeListHndl FREFTypes (short resFork)
  208. {
  209.     short        numFREFs, frefNum, numTypes = 0, saveResFork;
  210.     OSType        type, **fref;
  211.     TypeListHndl    typesHndl = NULL;
  212.     
  213.     if (resFork == kInvalidRefNum)
  214.         return NULL;
  215.         
  216.     saveResFork = CurResFile ();        // Save the current order of open resource forks
  217.     UseResFile (resFork);            // We'll read 'FREF' resources just from this file, since there may be any number of
  218.                                 //    open allication files and we don't want to end up with 'FREF's from all of them!
  219.     numFREFs = Count1Resources ('FREF');
  220.     if (numFREFs != 0) {
  221.         typesHndl = (TypeListHndl) NewHandle (numFREFs * sizeof (OSType) + sizeof (short));
  222.         if (typesHndl != NULL) {
  223.             for (numTypes = 0, frefNum = 1; frefNum <= numFREFs; frefNum++) {
  224.                 fref = (OSType **) Get1IndResource ('FREF', frefNum);
  225.                 if (fref != NULL) {
  226.                     type = **fref;
  227.                     ReleaseResource ((Handle) fref);
  228.                     if (type != 'APPL')                            // Don't count the 'APPL' type — nearly all
  229.                         (*typesHndl)->type[numTypes++] = type;    //    applications have an 'FREF' for this
  230.                 }
  231.             }
  232.             if (numTypes < numFREFs)
  233.                 SetHandleSize ((Handle) typesHndl, numTypes * sizeof (OSType) + sizeof (short));
  234.         }
  235.     }    
  236.     if (typesHndl != NULL)
  237.         (*typesHndl)->numTypes = numTypes;
  238.     
  239.     UseResFile (saveResFork);        // Restore the original order of open resource forks
  240.     return typesHndl;
  241. }
  242.  
  243. Boolean OpenableType (OSType fileType, TypeListHndl openableTypesHndl)
  244. {
  245.     short    i;
  246.     OSType    t, *tp;
  247.     
  248.     if (openableTypesHndl == NULL)
  249.         return FALSE;
  250.         
  251.     tp = &(*openableTypesHndl)->type[0];
  252.     for (i = (*openableTypesHndl)->numTypes; i > 0; i--, tp++) {
  253.         t = *tp;
  254.         if (fileType == 'fold' || fileType == 'disk') {
  255.             if (t == fileType)
  256.                 return TRUE;
  257.         } else if (t == '****' || t == fileType)
  258.             return TRUE;
  259.     }
  260.     return FALSE;        // If we got here, there's no match
  261. }
  262.  
  263. OSErr RefNumToFSSpec (short refNum, FSSpec *fss, Boolean *isResFork)
  264. {
  265.     FCBPBRec    pb;
  266.     OSErr        err;
  267.     
  268.     // See Inside Macintosh IV pp.178–180 for documentation of PBGetFCBInfo
  269.     // NOTE:    There is an apparent typo there — at the bottom of page 180, it says:
  270.     //
  271.     //            "FCBMdRByt (which corresponds to ioFCBFlags in the parameter
  272.     //            block for PBGetFCBInfo) contains flags that describe the status
  273.     //            of the file, as follows:…"
  274.     //
  275.     //        But experience shows that these flags are returned in the HIGH BYTE
  276.     //        of the ioFCBFlags field, not the whole word (in effect, in its low byte)
  277.     //        
  278.     //        Then again, maybe it's just a Pascal bit thing…
  279.     
  280.     pb.ioCompletion = NULL;
  281.     pb.ioVRefNum = 0;            // 0 == check all volumes
  282.     pb.ioNamePtr = fss->name;    // Yes, we need the name of the file — don't worry,
  283.                             //    HFSDispatch (in its guise of PBGetFCBInfo)
  284.                             //    doesn't move or purge memory (whew!)
  285.     pb.ioRefNum = refNum;
  286.     pb.ioFCBIndx = 0L;            // Get info on just this one file
  287.     
  288.     err = PBGetFCBInfoSync (&pb);    // NOTE:    For some strange reason, calling
  289.                                 //        PBGetFCBInfo (&pb, FALSE) here
  290.                                 //        instead gives us a major hang — I
  291.                                 //        have a feeling this is the fault of
  292.                                 //        THINK C's glue routines but I'm not
  293.                                 //        going to bother finding out for sure…
  294.     if (err != noErr)
  295.         return err;
  296.     
  297.     // Fill in the FSSpec — note that fss->name has already been filled in
  298.     fss->vRefNum = pb.ioFCBVRefNum;
  299.     fss->parID = pb.ioFCBParID;    // Inside Macintosh IV implies that pb.ioVRefNum
  300.                             //    returns the volume refnum, but in fact the call
  301.                             //    to PBGetFCBInfo doesn't affect it.  This makes
  302.                             //    sense when you think about it — if it DID return
  303.                             //    the volume refnum in ioVRefNum, you'd have
  304.                             //    to reset it to 0 in each of a sequence of indexed
  305.                             //    calls (with ioFCBIndx going from 1 to n == the
  306.                             //    number of open paths)
  307.     if (isResFork != NULL)
  308.         *isResFork = (pb.ioFCBFlags & 0x0200);
  309.         // 0x0200 == binary 00000010_00000000 — as I mentioned above, it's the
  310.         //    HIGH byte that counts.  Bit 9 of the word == bit 1 of the high byte — Inside
  311.         //    Macintosh IV (bottom of p.180) tells us "[bit] 1 … [is set] if the entry
  312.         //    describes a resource fork"
  313.     
  314. }
  315.  
  316. OSErr DirectoryContentsLoop (short vRefNum, long dirID, DCLActionProc actionProc, Boolean skipOnError, long refCon)
  317. {
  318.     // Loop through the directory designated by vRefNum and dirID, calling the function actionProc with the
  319.     //    parameter refcon for each thing in the directory.  This function does not recurse through subdirectories.
  320.     
  321.     CInfoPBRec    pb;
  322.     short        i;
  323.     OSErr        err = noErr;
  324.     Str63        name;
  325.     Boolean        keepGoing;
  326.     
  327.     pb.hFileInfo.ioCompletion = NULL;
  328.     pb.hFileInfo.ioNamePtr = &name[0];
  329.     
  330.     for (i = 1, keepGoing = TRUE; keepGoing; i++) {
  331.         pb.hFileInfo.ioVRefNum = vRefNum;
  332.         pb.hFileInfo.ioDirID = dirID;
  333.         pb.hFileInfo.ioFDirIndex = i;
  334.         err = PBGetCatInfoSync (&pb);
  335.         if (err == noErr)
  336.             keepGoing = (*actionProc) (&pb, refCon);
  337.         else if (err == fnfErr || !skipOnError)
  338.             keepGoing = FALSE;
  339.     }
  340.  
  341.     if (err == fnfErr)
  342.         err = noErr;
  343.  
  344.     return err;
  345. }
  346.  
  347.